'''
Author: 蚢
Date: 2021-05-17 15:20:19
Description: 
    1.可接受任意数量参数的函数 10
    2.强制使用关键字参数传递 23
    3.给函数参数增加元信息 30
    4.返回多个值 return 1,2,3
    5.定义有默认参数的函数
    6.定义匿名或内联函数
    7.匿名函数捕获变量值
    8.减少可调用对象的参数个数 55
    9.将单方法的类转换为函数 66
    10.带额外状态信息的回调函数 84
    11.内联回调函数 110
    12.访问闭包中的变量： nonlocal
'''

# 接受任意数量的位置参数
def avg(first, *rest):
    return (first + sum(rest)) / (1 + len(rest))

avg(1,2,3,4,5)    

# 接受任意数量的关键字参数
def key_fun(name, value, **attrs):
    keys = [key for key in attrs.items()]
    return [('name',name), ('age',value)] + keys

key_fun('hang','25',sex='true',hight=170)    

# 在*后面加关键字,则会使其函数强制使用关键字
def recv(*val, tip):
    pass

recv('notip') # TypeError: missing 1 required keyword-only argument: 'tip'；
recv(tip='a tip')

def add(x:int, y:int) -> int:
    return x + y

help(add), add.__annotations__    

# 匿名函数
add = lambda x,y:x+y
add(3,4)

# 匿名函数获取变量
x = 10
a = lambda y:x+y
x = 15
a(5) # 运行时绑定x,此时x=15
# 使用默认值
a = [lambda x: x+n for n in range(4)]
b = [lambda x,n=n:x+n for n in range(4)]
for i,j in zip(a,b):
    print(i(0),j(0))

def spam(a,b,c,d):
    print(a,b,c,d)

from functools import partial
# 原本4个参数,使用partial固定一个,不用传入参数
p_func = partial(spam,1)
p_func(2,3,4)
p_func(5,6,7)

# 可以使用闭包来将单个方法的类转换成函数。
class Demo:
    def __init__(self, a) -> None:
        self.a = a
    
    def mydo(self,b):
        print(self.a+b)
d = Demo(2)
d.mydo(3)

# 转换为 闭包: 给某个函数增加额外的状态信息的问题，都可以考虑使用闭包
def demo(a):
    def mydo(b):
        print(a+b)
    return mydo
d2 = demo(2)
d2(3)

# 带额外状态信息的回调函数
def apply_async(func, args, *, callback):
    
    result = func(*args)
    # 回调函数:
    callback(result)

def print_result(result):
    print("Got:", result)

def my_add(x, y):
    return x+y

apply_async(my_add, (2,3), callback=print_result)    
# 也可以用闭包实现 让回调函数访问其他变量
def make_hander():
    sequence = 0
    def hander(result):
        nonlocal sequence
        sequence += 1
        print('{} Got: {}'.format(sequence, result))

hander = make_hander()
apply_async(add, (2,3), callback=hander)

